﻿/*
   Copyright 2012 University of Southampton

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using uk.ac.soton.ses.DAL;
using System.Web.UI;
using System.Collections;
using System.Web;
using System.Web.UI.HtmlControls;

namespace uk.ac.soton.ses.WebControls
{
    /// <summary>
    /// A control that when passed an Experiment ID, finds all parameters and lists them hierarchically, permits editing and selecting of the parameter's parent.
    /// </summary>
    public class ExperimentParameterGridNew : CompositeControl
    {
        private int _parentExperimentID = -1;
        private int _parentParameterID = -1;
        ExperimentParameterGridEditLocation _editLocation = null;
        bool _showChildren = false;
        bool _showSystem = false;
        bool _recreateTreeRequired = false;

        private const string experimentparametergridjsloc = @"/_layouts/hdc/scripts/experimentparametergrid.js";
        private ExperimentParameterGridNew _topLevelGrid = null;
        private ExperimentParameterGridNew _editingGrid = null;

        private bool InEditMode
        { 
            get 
            {
                return (this._editLocation.ParentParameterID == this._parentParameterID && this._editLocation.EditEnabled == true);
            } 
        }
        private bool AtTopLevel
        {
            get
            {
                return this._parentParameterID == -1;
            }
        }

        /// <summary>
        /// This control requires an experiment ID in order to find the related parameters
        /// </summary>
        /// <param name="parentExperimentID">The experiment that contains the parameters to be shown in the grid.</param>
        public ExperimentParameterGridNew(int parentExperimentID)
            : this(parentExperimentID, -1, false, false, false)
        {
        }

        public ExperimentParameterGridNew(int parentExperimentID, int parentParameterID, ExperimentParameterGridEditLocation editLocation, bool showChildren, bool showSystem, ExperimentParameterGridNew topLevelGrid)
        {
            this._parentExperimentID = parentExperimentID;
            this._parentParameterID = parentParameterID;
            this._editLocation = editLocation;
            this._showChildren = showChildren;
            this._showSystem = showSystem;
            this._topLevelGrid = topLevelGrid;
        }

        /// <summary>
        /// This control requires the ID of the parent experiment. If a parent parameter is not available, pass -1 as the ID.
        /// </summary>
        /// <param name="parentExperimentID">The experiment that contains the parameters to be shown in the grid</param>
        /// <param name="parentParameterID">Given a parent parameter ID, its child parameters will be loaded. Without a parent parameter, the top level parameters will be loaded.</param>
        /// <param name="editMode">Whether to use textboxes or lables</param>
        public ExperimentParameterGridNew(int parentExperimentID, int parentParameterID, bool editMode, bool showChildren, bool showSystem)
        {
            this._parentExperimentID = parentExperimentID;
            this._parentParameterID = parentParameterID;
            //this._editMode = editMode;
            this._editLocation = new ExperimentParameterGridEditLocation(this._parentParameterID, editMode);
            this._showChildren = showChildren;
            this._showSystem = showSystem;
        }

        /// <summary>
        /// Setting up the control, telling ASP.NET we will be using control state (for our checkboxes)
        /// </summary>
        /// <param name="e">EventArgs passed by ASP.NET</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (this._parentParameterID == -1)
            {
                Page.RegisterRequiresControlState(this);
            }
        }

        /// <summary>
        /// Generates the grid and then data binds the grid.
        /// </summary>
        protected override void CreateChildControls()
        {
            this.Controls.Clear();
            //We aren't using ViewState as we have to rebind every time (because we need the data source to work out how many sub-grids to create)
            this.ClearChildViewState();
            //Create the controls
            this.CreateControlHierarchy();
            //Bind the grid
            this.Bind();
        }
        /// <summary>
        /// Create the controls we need for this CompositeControl and sets up the events
        /// </summary>
        private void CreateControlHierarchy()
        {
            //HtmlTable table = new HtmlTable();
            //this.Controls.Add(table);
            //HtmlTableRow row = new HtmlTableRow();
            //table.Controls.Add(row);
            //HtmlTableCell cell = new HtmlTableCell();
            //row.Controls.Add(cell);

            this.Controls.Add(new LiteralControl(@"<table><tr><td>"));

            //Add buttons for first row
            //Only one of these two buttons will be visible
            this.AddHeaderButton("Edit", "EditParameters", !this.InEditMode);
            this.AddHeaderButton("Save", "SaveParameters", this.InEditMode);
            this.AddSpace();
            this.AddHeaderButton("Cancel", "CancelEdit", this.InEditMode);
            this.AddSpace();
            this.AddHeaderButton("Add", "AddRecord");
            this.AddSpace();

            this.Controls.Add(new LiteralControl("</td><td>"));

            //Only add show children checkbox if we're at the top level
            if (this._parentParameterID == -1)
            {
                CheckBox chkShowChildren = new CheckBox();
                this.Controls.Add(chkShowChildren);
                chkShowChildren.ID = "cbShowChildren";
                chkShowChildren.Text = "Show all children";
                chkShowChildren.Checked = this._showChildren;
                chkShowChildren.AutoPostBack = false;
                chkShowChildren.Font.Bold = true;
                chkShowChildren.CheckedChanged += new EventHandler(chkShowChildren_CheckedChanged);
                chkShowChildren.CssClass = "ExperimentParametersChildrenCheckBox";

                CheckBox chkShowSystem = new CheckBox();
                this.Controls.Add(chkShowSystem);
                chkShowSystem.ID = "cbShowSystem";
                chkShowSystem.Text = "Show system parameters";
                chkShowSystem.Checked = this._showSystem;
                chkShowSystem.AutoPostBack = false;
                chkShowSystem.Font.Bold = true;
                chkShowSystem.CheckedChanged += new EventHandler(chkShowSystem_CheckedChanged);
                chkShowSystem.CssClass = "ExperimentParametersSystemCheckBox";

                Type scripttype = this.GetType();
                string scriptkey = "ExperimentParameterGridNew";
                if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(scripttype, scriptkey))
                {
                    this.Page.ClientScript.RegisterClientScriptInclude(scripttype, scriptkey, experimentparametergridjsloc);
                }
            }

            //Add the list view
            System.Web.UI.WebControls.ListView lv = new System.Web.UI.WebControls.ListView();
            this.Controls.Add(lv);
            lv.ID = "ListOfParameters";
            lv.LayoutTemplate = new ExperimentParameterListViewLayoutTemplate();
            lv.ItemTemplate = new ExperimentParameterListViewItemTemplate(this.InEditMode);
            lv.ItemDataBound += new EventHandler<ListViewItemEventArgs>(lv_ItemDataBound);
            lv.ItemCommand += new EventHandler<ListViewCommandEventArgs>(ProcessGridCommands);
            lv.DataKeyNames = new string[] { "ID" };

            this.Controls.Add(new LiteralControl(@"</td></tr></table>"));

            //Notify the parent that we are in edit mode so it can call us
            if (this.InEditMode)
            {
                if (this.AtTopLevel)
                {
                    this._editingGrid = this;
                }
                else
                {
                    RaiseBubbleEvent(this, new ExperimentParameterGridNotifyGridInEditModeEventArgs());
                }
            }
        }

        private LinkButton AddHeaderButton(string text, string command, bool visible = true)
        {
            LinkButton btn = new LinkButton();
            this.Controls.Add(btn);
            btn.ID = "btn" + text;
            btn.Text = text;
            btn.CommandName = command;
            //btn.Font.Bold = true;
            btn.CssClass = "ActionLink";
            //We are forced to do this because .NET always generates an ItemCommand event for the listview items whether we asked for it or not
            //Therefore, there is no point in adding our own handler as two events would then fire
            if (this.AtTopLevel)
            {
                btn.Command += new CommandEventHandler(ProcessGridCommands);
            }
            btn.Visible = visible;
            return btn;
        }

        private LiteralControl AddSpace()
        {
            LiteralControl lc = new LiteralControl();
            this.Controls.Add(lc);
            lc.ID = "Space" + this.Controls.Count;
            lc.Text = "&nbsp;";
            return lc;
        }

        /// <summary>
        /// Data bind the parameter editing grid with the parameters from the passed experiment
        /// </summary>
        private void Bind()
        {
            System.Web.UI.WebControls.ListView lv = (System.Web.UI.WebControls.ListView)this.FindControl("ListOfParameters");
            lv.DataSource = this.GetDataForParameterGrid();
            lv.DataBind();
        }

        /// <summary>
        /// Uses the experiment id that was passed to the control when it was created to look up the child parameters and return them as a list.
        /// If we also have a parent parameter, we will just list the parameters that are children of that parent parameter.
        /// </summary>
        /// <returns>The list of child parameters of the experiment, or the list of child parameters of the parent parameter depending on how the control is being used.</returns>
        private List<ExperimentParameter> GetDataForParameterGrid()
        {
            MaterialsMetadataContext dbcontext = HttpContext.Current.GetMaterialsDBContext();
            IEnumerable<ExperimentParameter> paramsToBind = null;
            //We have a parent parameter so we will just list the child params
            if (this._parentParameterID > -1)
            {
                paramsToBind = dbcontext.GetExperimentChildParameters(this._parentParameterID);
            }
            //We don't have a parent parameter, so we need to list parameters belonging to our experiment
            else
            {
                paramsToBind = dbcontext.GetExperimentTopLevelParameters(this._parentExperimentID,true);
            }
            return paramsToBind.OrderBy(param=>param.Position).ToList();
        }

        /// <summary>
        /// We need to record the edit mode and children mode otherwise it will be lost on post back (and we need to pass it to sub controls)
        /// </summary>
        /// <returns>An object containing control state</returns>
        protected override object SaveControlState()
        {
            //This method was inspired from a blog entry http://haacked.com/archive/2007/03/15/gain-control-of-your-control-state.aspx

            //Get the current control state of the base class so we don't interfere by overwriting it with our own
            object baseControlState = base.SaveControlState();

            //Generate a new control state, consisting the base's control state, plus ours
            object ourControlState = new object[] { baseControlState, this._editLocation, this._showChildren, this._showSystem };
            return ourControlState;

        }

        /// <summary>
        /// Obtain the edit mode and children mode from control state
        /// </summary>
        /// <param name="savedState">An object containing our saved entries, along with the base's control state</param>
        protected override void LoadControlState(object savedState)
        {
            //Try and cast the object as an array (if it is not an array, let the base handle it as we weren't passed the right data)
            object[] ourControlState = savedState as object[];
            if (ourControlState != null)
            {
                //The first item in the array is for the base class
                object baseControlState = ourControlState[0];
                //The second item should be the edit mode
                object editMode = ourControlState[1];
                //The third item should be the show children setting
                object showChildren = ourControlState[2];
                //The fourth item should the show system params setting
                object showSystem = ourControlState[3];
                //Check we have what we need to proceed
                if (editMode is ExperimentParameterGridEditLocation && showChildren is bool && showSystem is bool)
                {
                    this._editLocation = (ExperimentParameterGridEditLocation)editMode;
                    this._showChildren = (bool)showChildren;
                    this._showSystem = (bool)showSystem;
                    //Pass what's left to the base class
                    base.LoadControlState(baseControlState);
                }
                else
                {
                    //If we didn't get the right structure (two bools) then it's not our data
                    base.LoadControlState(savedState);
                }
            }
            else
            {
                base.LoadControlState(savedState);
            }
        }


        #region Event handling


        private void EnableEditParameters(int experimentParameterID)
        {
            this.SaveEditLocation(new ExperimentParameterGridEditLocation(experimentParameterID, true));
        }
        private void DisableEditParameters()
        {
            this.SaveEditLocation(new ExperimentParameterGridEditLocation(this._editLocation.ParentParameterID, false));
        }

        private void SaveEditLocation(ExperimentParameterGridEditLocation newEditLocation)
        {
            if (this.AtTopLevel)
            {
                this._editLocation = newEditLocation;
                this.RecreateChildControls();
            }
            else
            {
                this.RaiseBubbleEvent(this, new ExperimentParametersGridEditLocationEventArgs(newEditLocation));
            }
        }

        private void ProcessGridCommands(object sender, CommandEventArgs e)
        {
            //Work out which experiment parameter to use for the commands that need it
            int experimentParameterID;

            if (e is ListViewCommandEventArgs)
            {
                //This means that the command came from the grid (e.g. a delete command on a parameter)

                //Find the ListView that generated the command
                System.Web.UI.WebControls.ListView lv = (System.Web.UI.WebControls.ListView)this.FindControl("ListOfParameters");// (System.Web.UI.WebControls.ListView)sender;
                ListViewCommandEventArgs lvargs = (ListViewCommandEventArgs)e;

                //Find the row that generated the command
                ListViewDataItem lvDataItem = (ListViewDataItem)lvargs.Item;

                //Lookup the experiment parameter to find out which parameter the command was clicked on
                experimentParameterID = (int)lv.DataKeys[lvDataItem.DisplayIndex]["ID"];
            }
            else
            {
                //This means the command came from the wrapper control not the inner grid list view (e.g. Edit).

                //Find out the parent parameter ID from our stored data, which might be -1 if we are at the top
                experimentParameterID = this._parentParameterID;
            }

            if (e.CommandName != "CancelEdit" && this._editLocation.EditEnabled)
            {
                this.SaveEditGrid();
            }

            switch (e.CommandName)
            {
                case "AddRecord":
                    //Add a new parameter
                    this.AddParameterChildCommand(experimentParameterID);

                    //Set the edit index to the last record that was created (which will recreate the controls anyway)
                    this.EnableEditParameters(experimentParameterID);
                    break;

                case "EditParameters":
                    //Set the edit index (which recreates the controls)
                    this.EnableEditParameters(experimentParameterID);
                    break;

                case "CancelEdit":
                case "SaveParameters":
                    //Note that we saved the data already for the SaveParameters command
                    this.DisableEditParameters();
                    break;

                //LIST VIEW ITEM COMMANDS

                //Delete a parameter completely
                case "DeleteParameter":
                    this.DeleteParameter(experimentParameterID, false);
                    this.RecreateTree();
                    break;

                //Delete a parameter and all its children
                case "DeleteParameterTree":
                    this.DeleteParameter(experimentParameterID, true);
                    this.RecreateTree();
                    break;

                //Add a parameter beneath another parameter
                case "AddParameterChild":
                    //Add a child parameter
                    this.AddParameterChildCommand(experimentParameterID);

                    //Set the edit index to the last record that was created (which will recreate the controls anyway)
                    this.EnableEditParameters(this._parentExperimentID);
                    break;
            }

        }

        private void DeleteParameter(int experimentParameterID, bool deleteTree)
        {
            //Load a database class as we'll need to process data
            MaterialsMetadataContext dbcontext = HttpContext.Current.GetMaterialsDBContext();

            bool deletesuccess = false;

            if (deleteTree)
            {
                deletesuccess = dbcontext.DeleteExperimentParameterTree(experimentParameterID, true, true);
            }
            else
            {
                deletesuccess = dbcontext.DeleteExperimentParameter(experimentParameterID, true);
            }
        }

        /// <summary>
        /// Records whether to show children which is passed to child controls
        /// </summary>
        /// <param name="sender">Hopefully, the checkbox that has changed</param>
        /// <param name="e">EventArgs passed by ASP.NET</param>
        private void chkShowChildren_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            if (cb != null)
            {
                this._showChildren = cb.Checked;
                this._recreateTreeRequired = true;
                //this.RecreateChildControls();
            }
        }

        /// <summary>
        /// Records whether to show children which is passed to child controls
        /// </summary>
        /// <param name="sender">Hopefully, the checkbox that has changed</param>
        /// <param name="e">EventArgs passed by ASP.NET</param>
        private void chkShowSystem_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            if (cb != null)
            {
                this._showSystem = cb.Checked;
                this._recreateTreeRequired = true;
                //this.RecreateChildControls();
            }
        }

        private void AddParameterChildCommand(int parentParameterID)
        {
            MaterialsMetadataContext dbcontext = HttpContext.Current.GetMaterialsDBContext();
            Experiment parentExp = dbcontext.GetExperimentByID(this._parentExperimentID);
            //Check the parent experiment record still exists
            if (parentExp != null)
            {
                //Create a new parameter
                ExperimentParameter newParam = parentExp.SaveParameterValue(dbcontext, String.Format("Param added {0}", DateTime.Now), "", true);

                //If we have a parent parameter, create a link to it (this is when the grid view is a nested parameter)
                if (parentParameterID > -1)
                {
                    //If we have a parent parameter, create a link to it (this is when the grid view is a nested parameter)
                    //Make sure we can find the parent
                    ExperimentParameter parentParam = dbcontext.GetExperimentParameterByID(parentParameterID);
                    if (parentParam != null)
                    {
                        //Create the link
                        parentParam.AddChildParameter(dbcontext, newParam);
                    }
                }
                dbcontext.SaveChanges();

                dbcontext.MoveParameterToLastInLevel(newParam.ID);
                dbcontext.SaveChanges();
            }
        }

        private void SaveEditGrid()
        {
            if (!this.AtTopLevel)
            {
                this._topLevelGrid.SaveEditGrid();
            }
            else if (this._editingGrid != null && this._editingGrid.InEditMode)
            {
                this.SaveParametersInGrid(this._editingGrid);
            }
        }

        private void SaveParametersInGrid(ExperimentParameterGridNew gridToSave)
        {
            MaterialsMetadataContext dbcontext = HttpContext.Current.GetMaterialsDBContext();
            System.Web.UI.WebControls.ListView lv = (System.Web.UI.WebControls.ListView)gridToSave.FindControl("ListOfParameters");

            for (int i = 0; i < lv.Items.Count; i++)
            {
                ListViewDataItem thisItem = (ListViewDataItem)lv.Items[i];
                int thisParameterID = (int)lv.DataKeys[i]["ID"];
                Control ph = thisItem.Controls[0];
                Control tablerow = ph.Controls[0];
                TextBox txt_ParamName = null;
                TextBox txt_ParamValue = null;
                TextBox txt_ParamUnit = null;
                TextBox txt_ParamType = null;
                TextBox txt_ParamPosition = null;
                CheckBox cb_ParamIsCompulsory = null;
                txt_ParamName = tablerow.FindControl("txtName") as TextBox;
                txt_ParamValue = tablerow.FindControl("txtValue") as TextBox;
                txt_ParamUnit = tablerow.FindControl("txtUnit") as TextBox;
                txt_ParamType = tablerow.FindControl("txtType") as TextBox;
                txt_ParamPosition = tablerow.FindControl("txtPosition") as TextBox;
                cb_ParamIsCompulsory = tablerow.FindControl("cbIsCompulsory") as CheckBox;

                //Update the database
                if (txt_ParamValue != null && txt_ParamName != null && txt_ParamUnit != null && txt_ParamType != null && cb_ParamIsCompulsory != null && txt_ParamPosition!=null)
                {
                    string newName = txt_ParamName.Text;
                    string newValue = txt_ParamValue.Text;
                    string newUnit = txt_ParamUnit.Text;
                    string newType = txt_ParamType.Text;
                    bool newIsCompulsory = cb_ParamIsCompulsory.Checked;
                    string newPositionTxt = txt_ParamPosition.Text;

                    //Position can be null, so we have to let null values through, ignoring other strings
                    try
                    {
                        int? newPosition = String.IsNullOrEmpty(newPositionTxt) ? null : (int?)int.Parse(newPositionTxt);
                        bool savesuccess = dbcontext.UpdateExperimentParameter(thisParameterID, newName, newValue, newUnit, newType, newIsCompulsory, newPosition);
                        if (savesuccess)
                        {
                            dbcontext.SaveChanges();
                        }
                    }
                    catch (Exception e)
                    {
                        if (e is OverflowException || e is FormatException)
                        {
                            //Do nothing if the position field is not an integer
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }
        }

          
        /// <summary>
        /// On each row of the grid, we decide if there are any sub parameters and dynamically create a sub editing grid.
        /// </summary>
        /// <param name="sender">The ListView</param>
        /// <param name="e">ListViewItemEventArgs passed by ASP.NET</param>
        private void lv_ItemDataBound(object sender, ListViewItemEventArgs e)
        {
            ListViewDataItem lvDataItem = (ListViewDataItem)e.Item;
            ExperimentParameter experimentParameter = lvDataItem.DataItem as ExperimentParameter;

            TableCell tdOperations = lvDataItem.FindControl("tdOperations") as TableCell;
            //tdOperations.Controls.Add(new LiteralControl("&nbsp;"));

            //Uncomment this code to enable the drop down menu for moving parameters around
            //ExperimentParameterLinkControl linkControl = new ExperimentParameterLinkControl(this._parentExperimentID, this._parentParameterID, experimentParameter);
            //tdOperations.Controls.Add(linkControl);
            //linkControl.ID = "ParamLinkControl";

            //Find out if we have any more child parameters and if so, create a sub table
            MaterialsMetadataContext dbcontext = HttpContext.Current.GetMaterialsDBContext();
            List<ExperimentParameter> linkedParams = dbcontext.GetExperimentChildParameters(experimentParameter.ID).ToList();

            bool systemParameter = experimentParameter.IsSystemParameter;

            //Sort out system parameter rows so they can be hidden
            if (systemParameter)
            {
                //Find the controls placeholder
                PlaceHolder controlsPlaceHolder = lvDataItem.FindControl("ControlsContainer") as PlaceHolder;
                //Get the table row so we can edit its css class
                TableRow parameterRow = controlsPlaceHolder.FindControl("parameterrow") as TableRow;
                //Set this as a system parameter row
                parameterRow.CssClass += " SystemParameterRow";

                //Hide the row if necessary
                if (!this._showSystem)
                {
                    parameterRow.Style["display"] = "none";
                }

            }

            //Add a sub parameter grid if the parameter has children
            if (linkedParams.Count > 0)
            {
                //Add a space
                tdOperations.Controls.Add(new LiteralControl("&nbsp;|&nbsp;"));

                //Add a button that can be used to delete the parameter tree
                LinkButton btnDeleteTree = new LinkButton() { Text = "Delete&nbsp;tree" };
                tdOperations.Controls.Add(btnDeleteTree);
                btnDeleteTree.CommandName = "DeleteParameterTree";
                btnDeleteTree.CssClass = "ActionLink";

                //Add a space
                tdOperations.Controls.Add(new LiteralControl("&nbsp;&nbsp;"));

                //Add a label that can be used to show/hide the sub-parameters
                Label childParamLabel = new Label();
                tdOperations.Controls.Add(childParamLabel);
                childParamLabel.ID = "ChildParametersLabel";
                childParamLabel.CssClass = "ChildParametersShowLabel";
                childParamLabel.Text = (this._showChildren ? "&mdash;" : "+");

                //Find the place holder that we can add the new table row to (added in the ListView Item Template)
                PlaceHolder controlsPlaceHolder = lvDataItem.FindControl("ControlsContainer") as PlaceHolder;

                //Generate the row
                TableRow additionalTR = new TableRow();
                controlsPlaceHolder.Controls.Add(additionalTR);
                
                //If it is a system row, allow it to be hidden
                if (systemParameter)
                {
                    additionalTR.CssClass += " SystemParameterRow";
                    //Hide the row if necessary
                    if (!this._showSystem)
                    {
                        additionalTR.Style["display"] = "none";
                    }
                }

                TableCell tc = new TableCell() { ColumnSpan = 6 };
                additionalTR.Controls.Add(tc);

                //Add a panel (which renders as a DIV) that can be used to hide the listview
                Panel lvPanel = new Panel();
                tc.Controls.Add(lvPanel);
                lvPanel.ID = "SubExperimentParametersGridPanel";
                lvPanel.CssClass = "SubExperimentParametersGrid";
                //Hide the panel now if it's not needed
                if (!this._showChildren)
                {
                    lvPanel.Style["display"] = "none";
                }
                //Generate the sub-parameter grid
                ExperimentParameterGridNew gridNested = new ExperimentParameterGridNew(this._parentExperimentID, experimentParameter.ID, this._editLocation, this._showChildren, this._showSystem, this._topLevelGrid ?? this);
                lvPanel.Controls.Add(gridNested);
                gridNested.ID = "ChildParameters";

            }
        }

        private void RecreateTree()
        {
            if (this.AtTopLevel)
            {
                this.RecreateChildControls();
            }
            else
            {
                this.RaiseBubbleEvent(this, new RebindRequiredEventArgs());
            }
        }

        public void Recreate()
        {
            base.RecreateChildControls();
        }

        protected override bool OnBubbleEvent(object source, EventArgs args)
        {
            if (this.AtTopLevel)
            {
                //We will only rebind if we are the top level grid
                if (args is RebindRequiredEventArgs)
                {
                    this.RecreateChildControls();
                    return true;
                }
                else if (args is ExperimentParametersGridEditLocationEventArgs)
                {
                    ExperimentParametersGridEditLocationEventArgs editArgs = (ExperimentParametersGridEditLocationEventArgs)args;
                    this.SaveEditLocation(editArgs.NewEditLocation);
                    return true;
                }
                else if (args is ExperimentParameterGridNotifyGridInEditModeEventArgs)
                {
                    this._editingGrid = source as ExperimentParameterGridNew;
                    return true;
                }
            }

            //We didn't handle the event, so pass it on
            return base.OnBubbleEvent(source, args);
        }

        /// <summary>
        /// Override PreRender to see whether we need to recreate the tree (such as show children/system checkboxes changed)
        /// </summary>
        /// <param name="e">Standard .NET argument</param>
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            if (this._recreateTreeRequired)
            {
                //Only recreate the tree if we're at the top level
                if (this.AtTopLevel)
                {
                    this.RecreateTree();
                }
                //Otherwise pass the request to the top grid
                else
                {
                    this._topLevelGrid.RecreateTree();
                }
            }
        }

        #endregion

        //This code has been left in commented in case the new saving method fails and it is needed for reference:
        //private void SaveParametersGrid(ListViewDataItem lvDataItem)
        //{
        //    ExperimentParameterGridNew gridToSave = null;
        //    if (lvDataItem != null)
        //    {
        //        gridToSave = this.GetListViewSubGrid(lvDataItem.DisplayIndex);
        //    }
        //    else
        //    {
        //        gridToSave = this;
        //    }
        //    this.SaveParametersCommand(gridToSave);
        //    this.DisableEditParameters();
        //}

        //private ExperimentParameterGridNew GetListViewSubGrid(int listViewIndex)
        //{
        //    System.Web.UI.WebControls.ListView lv = (System.Web.UI.WebControls.ListView)this.FindControl("ListOfParameters");
        //    ListViewDataItem lvDataItem = lv.Items[listViewIndex] as ListViewDataItem;
        //    if (lvDataItem != null)
        //    {
        //        Control placeHolder = lvDataItem.Controls[0];
        //        if (placeHolder.Controls.Count >= 2)
        //        {
        //            Control tableRow = placeHolder.Controls[1];
        //            Control tableCell = tableRow.Controls[0];
        //            Control panel = tableCell.Controls[0];
        //            ExperimentParameterGridNew grid = panel.Controls[0] as ExperimentParameterGridNew;
        //            return grid;
        //        }
        //        else
        //        {
        //            throw new InvalidOperationException("There is no sub grid");
        //        }
        //    }
        //    else
        //    {
        //        throw new KeyNotFoundException(String.Format("ListView index {0} not found", listViewIndex));
        //    }
        //}

    }
}
